﻿using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace Gmantis.Controls.DataGrid
{
    internal class ViewColumn : IDataGridViewItem
    {
        // Fields
        private double? _desiredWidth;
        private DataGridGroupColumnHeaderPresenter _groupHeaderPresenter;
        private DataGridColumnHeaderPresenter _headerPresenter;
        private double? _renderWidth;
        private int index;

        // Methods
        public ViewColumn(DataGridView view, DataGridColumn column)
        {
            this._desiredWidth = null;
            this._renderWidth = null;
            this.index = -1;
            this.View = view;
            this.Column = column;
        }

        public ViewColumn(DataGridView view, int index)
        {
            this._desiredWidth = null;
            this._renderWidth = null;
            this.index = -1;
            this.View = view;
            this.index = index;
        }

        private static void ApplyColumnHeaderStyle(DataGridColumnHeaderPresenter columnHeader, DataGridColumn column, DataGrid dataGrid)
        {
            Style columnHeaderPresenterStyle = null;
            if (column != null)
            {
                columnHeaderPresenterStyle = column.GetColumnHeaderPresenterStyle();
            }
            else
            {
                columnHeaderPresenterStyle = dataGrid.ColumnHeaderStyle;
            }
            if (columnHeaderPresenterStyle != null)
            {
                columnHeader.Style = columnHeaderPresenterStyle;
            }
        }

        private void ApplyGroupColumnHeaderStyle(DataGridGroupColumnHeaderPresenter groupColumnHeader, DataGrid dataGrid)
        {
            if (groupColumnHeader.Style == null)
            {
                Style groupColumnHeaderPresenterStyle = this.Column.GetGroupColumnHeaderPresenterStyle();
                if (groupColumnHeaderPresenterStyle != null)
                {
                    groupColumnHeader.Style = groupColumnHeaderPresenterStyle;
                }
            }
        }

        public void ClearCachedData()
        {
            this._desiredWidth = null;
        }

        private static void colHeader_AutoSized(object sender, EventArgs e)
        {
            DataGridColumnHeaderPresenter presenter = (DataGridColumnHeaderPresenter)sender;
            DataGrid tag = (DataGrid)presenter.Tag;
            tag.LeadingColumnWidth = DataGridLength.Auto;
        }

        private static void colHeader_Resized(object sender, PropertyChangedEventArgs<double> e)
        {
            DataGridColumnHeaderPresenter presenter = (DataGridColumnHeaderPresenter)sender;
            DataGrid tag = (DataGrid)presenter.Tag;
            if (tag.Model.GroupManager.GroupCount != 0)
            {
                tag.LeadingColumnWidth = new DataGridLength(e.NewValue);
            }
        }

        private DataGridColumnHeaderPresenter CreateColumnHeaderPresenter()
        {
            DataGridColumnHeaderPresenter colHeader = this.Column.CreateColumnHeaderPresenter();
            InitializeColumnHeaderPresenterStyle(this.DataGrid, this.Column, colHeader);
            return colHeader;
        }

        public static DataGridColumnHeaderPresenter CreateIndentColumnHeaderPresenter(DataGrid dataGrid)
        {
            DataGridColumnHeaderPresenter colHeader = new DataGridColumnHeaderPresenter();
            InitializeColumnHeaderPresenterStyle(dataGrid, null, colHeader);
            colHeader.Tag = dataGrid;
            colHeader.SetBinding(DataGridColumnHeaderPresenter.CanUserResizeProperty, new Binding().From<DataGrid>(dataGrid, x => x.CanUserResizeColumns));
            colHeader.Resized += new EventHandler<PropertyChangedEventArgs<double>>(ViewColumn.colHeader_Resized);
            colHeader.Resizing += new EventHandler<PropertyChangedEventArgs<double>>(ViewColumn.colHeader_Resized);
            colHeader.AutoSized += new EventHandler(ViewColumn.colHeader_AutoSized);
            return colHeader;
        }

        internal void FinalizeColumnHeaderPresenter()
        {
            if (this._headerPresenter != null)
            {
                DataGridColumnHeaderPresenter headerPresenter = this._headerPresenter;
                this.FinalizeColumnHeaderPresenter(headerPresenter);
                this._headerPresenter = null;
                this.View.ColumnsHeaderPanel.RemoveChild(headerPresenter);
                headerPresenter.ViewColumn = null;
            }
        }

        internal void FinalizeColumnHeaderPresenter(DataGridColumnHeaderPresenter headerPresenter)
        {
            this.DataGrid.OnUnloadedColumnHeaderPresenter(new DataGridColumnEventArgs(this.Column));
            headerPresenter.Resized -= new EventHandler<PropertyChangedEventArgs<double>>(this.HeaderPresenter_Resized);
            headerPresenter.Resizing -= new EventHandler<PropertyChangedEventArgs<double>>(this.HeaderPresenter_Resizing);
            headerPresenter.AutoSized -= new EventHandler(this.HeaderPresenter_AutoSized);
            headerPresenter.FilterChanged -= new EventHandler<PropertyChangedEventArgs<DataGridFilterState>>(this.HeaderPresenter_FilterChanged);
            headerPresenter.FilterOpened -= new EventHandler<DataGridColumnValueEventArgs<IDataGridFilter>>(this.HeaderPresenter_FilterOpened);
            headerPresenter.FilterLoading -= new EventHandler<DataGridColumnEditableValueEventArgs<IDataGridFilter>>(this.HeaderPresenter_FilterLoading);
            headerPresenter.ClearValue(DataGridColumnHeaderPresenter.IsFilteringProperty);
            headerPresenter.ClearValue(DataGridColumnHeaderPresenter.CanUserResizeProperty);
            headerPresenter.ClearValue(DataGridColumnHeaderPresenter.CanUserFilterProperty);
            headerPresenter.Unload();
            this.Column.UnbindColumnHeaderPresenter(headerPresenter);
        }

        private void FinalizeGroupColumnHeaderPresenter()
        {
            if (this._groupHeaderPresenter != null)
            {
                this.View.GroupingPresenter.InvalidateGroups();
                this._groupHeaderPresenter.ViewColumn = null;
                this._groupHeaderPresenter = null;
            }
        }

        public void FinalizeViewItem()
        {
        }

        public object GetColumnHeaderPresenterRecyclingKey()
        {
            object columnHeaderPresenterRecyclingKey = this.Column.GetColumnHeaderPresenterRecyclingKey();
            Style columnHeaderPresenterStyle = this.Column.GetColumnHeaderPresenterStyle();
            if (columnHeaderPresenterRecyclingKey == null)
            {
                return null;
            }
            return new TwoMembersRecyclingKey(columnHeaderPresenterRecyclingKey, columnHeaderPresenterStyle);
        }

        public DataGridGroupColumnHeaderPresenter GetGroupHeaderPresenter(bool forceCreate)
        {
            if ((this._groupHeaderPresenter == null) && forceCreate)
            {
                this._groupHeaderPresenter = this.Column.CreateGroupColumnHeaderPresenter();
                this._groupHeaderPresenter.IsInGroupingPanel = true;
                this._groupHeaderPresenter.SetBinding(Control.IsEnabledProperty, new Binding().From<DataGrid>(this.DataGrid, x => x.CanUserGroup));
                this.InitializeGroupColumnHeaderPresenter();
            }
            return this._groupHeaderPresenter;
        }

        public DataGridColumnHeaderPresenter GetHeaderPresenter(bool forceCreate)
        {
            Func<UIElement> creator = null;
            if ((this._headerPresenter == null) && forceCreate)
            {
                if (creator == null)
                {
                    creator = () => this.CreateColumnHeaderPresenter();
                }
                this._headerPresenter = (DataGridColumnHeaderPresenter)this.View.ColumnsHeaderPanel.GetChild(this.GetColumnHeaderPresenterRecyclingKey(), creator);
                this.InitializeColumnHeaderPresenter();
                this.DataGrid.OnLoadedColumnHeaderPresenter(new DataGridColumnEventArgs(this.Column));
            }
            return this._headerPresenter;
        }

        private void HeaderPresenter_AutoSized(object sender, EventArgs e)
        {
            this.DesiredWidth = 0.0;
            this.Column.Width = DataGridLength.Auto;
            this.View.InvalidatePanelsMeasure();
            this.View.OnColumnResized(this.Column, this.Column.ViewColumn.DesiredWidth);
        }

        private void HeaderPresenter_FilterChanged(object sender, PropertyChangedEventArgs<DataGridFilterState> e)
        {
            try
            {
                this.DataGrid.FilterBy(this.Column, e.NewValue, true);
            }
            catch (DataGridFilterException)
            {
            }
            catch (DataGridFinalizeEditingException)
            {
            }
        }

        private void HeaderPresenter_FilterLoading(object sender, DataGridColumnEditableValueEventArgs<IDataGridFilter> e)
        {
            this.View.OnFilterLoading(e);
        }

        private void HeaderPresenter_FilterOpened(object sender, DataGridColumnValueEventArgs<IDataGridFilter> e)
        {
            this.View.OnFilterOpened(e);
        }

        private void HeaderPresenter_Resized(object sender, PropertyChangedEventArgs<double> e)
        {
            this.Column.Width = new DataGridLength(e.NewValue);
            this.View.OnColumnResized(this.Column, e.NewValue);
        }

        private void HeaderPresenter_Resizing(object sender, PropertyChangedEventArgs<double> e)
        {
            this.Column.Width = new DataGridLength(e.NewValue);
            this.View.OnColumnResizing(this.Column, e.NewValue);
        }

        internal void InitializeColumnHeaderPresenter()
        {
            this._headerPresenter.ViewColumn = this;
            this.InitializeColumnHeaderPresenter(this._headerPresenter);
        }

        internal void InitializeColumnHeaderPresenter(DataGridColumnHeaderPresenter headerPresenter)
        {
            headerPresenter.Resized += new EventHandler<PropertyChangedEventArgs<double>>(this.HeaderPresenter_Resized);
            headerPresenter.Resizing += new EventHandler<PropertyChangedEventArgs<double>>(this.HeaderPresenter_Resizing);
            headerPresenter.AutoSized += new EventHandler(this.HeaderPresenter_AutoSized);
            headerPresenter.FilterChanged += new EventHandler<PropertyChangedEventArgs<DataGridFilterState>>(this.HeaderPresenter_FilterChanged);
            headerPresenter.FilterOpened += new EventHandler<DataGridColumnValueEventArgs<IDataGridFilter>>(this.HeaderPresenter_FilterOpened);
            headerPresenter.FilterLoading += new EventHandler<DataGridColumnEditableValueEventArgs<IDataGridFilter>>(this.HeaderPresenter_FilterLoading);
            headerPresenter.SetBinding(DataGridColumnHeaderPresenter.CanUserResizeProperty, new Binding().From<DataGridColumn>(this.Column, x => x.ActualCanUserResize));
            headerPresenter.SetBinding(DataGridColumnHeaderPresenter.CanUserFilterProperty, new Binding().From<DataGridColumn>(this.Column, x => x.ActualCanUserFilter));
            headerPresenter.SetBinding(DataGridColumnHeaderPresenter.OptionsVisibilityProperty, new Binding().From<DataGrid>(this.DataGrid, x => x.ColumnHeaderOptionsVisibility));
            Binding binding = new Binding
            {
                Converter = CustomConverter.Create((value, type, parameters, culture) => value != null)
            };
            headerPresenter.SetBinding(DataGridColumnHeaderPresenter.IsFilteringProperty, binding.From<DataGridColumn>(this.Column, x => x.FilterState));
            headerPresenter.Load();
            Func<DataGridColumn, object> func = delegate(DataGridColumn column)
            {
                FrameworkElement header = column.Header as FrameworkElement;
                if ((header != null) && (header.Parent is ContentControl))
                {
                    (header.Parent as ContentControl).Content = null;
                }
                if (column.Header is string)
                {
                    return new TextBlock { Text = (string)column.Header, VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Left, TextTrimming = TextTrimming.WordEllipsis };
                }
                return column.Header;
            };
            headerPresenter.Content = func(this.Column);
            this.Column.BindColumnHeaderPresenter(headerPresenter);
        }

        internal static void InitializeColumnHeaderPresenterStyle(DataGrid dataGrid, DataGridColumn column, DataGridColumnHeaderPresenter colHeader)
        {
            ApplyColumnHeaderStyle(colHeader, column, dataGrid);
            colHeader.SetBinding<DataGrid>(Control.BackgroundProperty, dataGrid, dg => dg.HeaderBackground);
            colHeader.SetBinding<DataGrid>(Control.ForegroundProperty, dataGrid, dg => dg.HeaderForeground);
            colHeader.SetBinding<DataGrid>(Control.BorderBrushProperty, dataGrid, dg => dg.BorderBrush);
            colHeader.SetBinding<DataGrid>(DataGridColumnHeaderPresenter.SelectedBackgroundProperty, dataGrid, dg => dg.SelectedBackground);
            colHeader.SetBinding<DataGrid>(DataGridColumnHeaderPresenter.PressedBrushProperty, dataGrid, dg => dg.PressedBrush);
            colHeader.SetBinding<DataGrid>(DataGridColumnHeaderPresenter.MouseOverBrushProperty, dataGrid, dg => dg.MouseOverBrush);
        }

        private void InitializeGroupColumnHeaderPresenter()
        {
            this._groupHeaderPresenter.ViewColumn = this;
            this.ApplyGroupColumnHeaderStyle(this._groupHeaderPresenter, this.DataGrid);
            Binding binding = new Binding
            {
                Converter = CustomConverter.Create(delegate(object value, Type type, object parameter, CultureInfo culture)
                {
                    FrameworkElement element = value as FrameworkElement;
                    if ((element != null) && (element.Parent is ContentControl))
                    {
                        (element.Parent as ContentControl).Content = null;
                    }
                    if (value is string)
                    {
                        return new TextBlock { Text = (string)value, VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Left, TextTrimming = TextTrimming.WordEllipsis };
                    }
                    return value;
                })
            };
            this._groupHeaderPresenter.SetBinding(ContentControl.ContentProperty, binding.From<DataGridColumn>(this.Column, x => x.ActualGroupHeader));
            this._groupHeaderPresenter.SetBinding<DataGridGroupingPresenter>(Control.BackgroundProperty, this.View.GroupingPresenter, dg => dg.Background);
            this._groupHeaderPresenter.SetBinding<DataGridGroupingPresenter>(Control.ForegroundProperty, this.View.GroupingPresenter, dg => dg.Foreground);
            this._groupHeaderPresenter.SetBinding<DataGridGroupingPresenter>(Control.BorderBrushProperty, this.View.GroupingPresenter, dg => dg.BorderBrush);
            this._groupHeaderPresenter.SetBinding<DataGrid>(Control.BorderThicknessProperty, this.DataGrid, dg => dg.BorderThickness);
            this._groupHeaderPresenter.SetBinding<DataGrid>(DataGridColumnHeaderPresenter.SelectedBackgroundProperty, this.DataGrid, dg => dg.SelectedBackground);
            this._groupHeaderPresenter.SetBinding<DataGrid>(DataGridColumnHeaderPresenter.PressedBrushProperty, this.DataGrid, dg => dg.PressedBrush);
            this._groupHeaderPresenter.SetBinding<DataGrid>(DataGridColumnHeaderPresenter.MouseOverBrushProperty, this.DataGrid, dg => dg.MouseOverBrush);
        }

        public void InitializeViewItem()
        {
        }

        internal void Unload(bool unloadCells = true, bool unloadColumnHeaders = true, bool unloadGroupRows = true)
        {
            if (unloadColumnHeaders)
            {
                this.FinalizeGroupColumnHeaderPresenter();
                this.FinalizeColumnHeaderPresenter();
            }
            if (unloadGroupRows)
            {
                this.View.UnloadGroupRowsPresenters(this);
            }
            if (unloadCells)
            {
                this.View.UnloadCellsPresenters(this);
                this.View.InvalidatePanelsMeasure();
            }
        }

        public void UpdateMouseOver()
        {
            this.Column.UpdateMouseOver();
            if (this._headerPresenter != null)
            {
                this._headerPresenter.UpdateMouseOver();
            }
            if (this._groupHeaderPresenter != null)
            {
                this._groupHeaderPresenter.UpdateMouseOver();
            }
        }

        public void UpdateSelection()
        {
            this.Column.UpdateSelection();
            if (this._headerPresenter != null)
            {
                this._headerPresenter.UpdateSelection();
            }
        }

        // Properties
        public DataGridColumn Column { get; private set; }

        public int ColumnDisplayIndex
        {
            get
            {
                return this.Column.DisplayIndex;
            }
        }

        public DataGrid DataGrid
        {
            get
            {
                return this.View.DataGrid;
            }
        }

        public double DesiredWidth
        {
            get
            {
                double? nullable = this._desiredWidth;
                if (!nullable.HasValue)
                {
                    return 0.0;
                }
                return nullable.GetValueOrDefault();
            }
            set
            {
                double num = Math.Max(this.MinWidth, Math.Min(this.MaxWidth, Math.Ceiling(value)));
                double? nullable = this._desiredWidth;
                double num2 = num;
                if ((nullable.GetValueOrDefault() != num2) || !nullable.HasValue)
                {
                    this._desiredWidth = new double?(num);
                    DataGridUnitType type = this.Width.Type;
                    if (type != DataGridUnitType.Auto)
                    {
                        if (type != DataGridUnitType.AutoStar)
                        {
                            return;
                        }
                    }
                    else
                    {
                        this.View.OnColumnActualWidthChanged(this);
                        return;
                    }
                    this._renderWidth = null;
                    this.View.OnColumnActualWidthChanged(this);
                }
            }
        }

        public bool HasRenderWidth
        {
            get
            {
                switch (this.Width.Type)
                {
                    case DataGridUnitType.Auto:
                        return this._desiredWidth.HasValue;

                    case DataGridUnitType.Pixel:
                        return true;

                    case DataGridUnitType.Star:
                        return this._renderWidth.HasValue;

                    case DataGridUnitType.AutoStar:
                        if (!this._renderWidth.HasValue)
                        {
                            return false;
                        }
                        return this._desiredWidth.HasValue;
                }
                return false;
            }
        }

        public int Index
        {
            get
            {
                if (this.index >= 0)
                {
                    return this.index;
                }
                return this.Column.Index;
            }
        }

        public double MaxWidth
        {
            get
            {
                return this.Column.ActualMaxWidth;
            }
        }

        public double MeasureWidth
        {
            get
            {
                switch (this.Width.Type)
                {
                    case DataGridUnitType.Pixel:
                        return Math.Min(this.MaxWidth, Math.Max(this.MinWidth, this.Width.Value));

                    case DataGridUnitType.Star:
                        {
                            double? nullable = this._renderWidth;
                            if (nullable.HasValue)
                            {
                                return nullable.GetValueOrDefault();
                            }
                            return this.MaxWidth;
                        }
                }
                return this.MaxWidth;
            }
        }

        public double MinRenderWidth
        {
            get
            {
                switch (this.Width.Type)
                {
                    case DataGridUnitType.Auto:
                    case DataGridUnitType.AutoStar:
                        return this.DesiredWidth;

                    case DataGridUnitType.Pixel:
                        return this.MeasureWidth;
                }
                return this.MinWidth;
            }
        }

        public double MinWidth
        {
            get
            {
                return this.Column.ActualMinWidth;
            }
        }

        public double Offset { get; set; }

        public double RenderWidth
        {
            get
            {
                switch (this.Width.Type)
                {
                    case DataGridUnitType.Auto:
                        return this.DesiredWidth;

                    case DataGridUnitType.Pixel:
                        return this.MeasureWidth;

                    case DataGridUnitType.Star:
                        {
                            double? nullable = this._renderWidth;
                            if (nullable.HasValue)
                            {
                                return nullable.GetValueOrDefault();
                            }
                            return this.MinWidth;
                        }
                    case DataGridUnitType.AutoStar:
                        {
                            double? nullable2 = this._renderWidth;
                            if (nullable2.HasValue)
                            {
                                return nullable2.GetValueOrDefault();
                            }
                            return this.DesiredWidth;
                        }
                }
                return this.MinWidth;
            }
            set
            {
                double num = Math.Max(this.MinWidth, Math.Min(this.MaxWidth, value));
                double? nullable = this._renderWidth;
                double num2 = num;
                if ((nullable.GetValueOrDefault() != num2) || !nullable.HasValue)
                {
                    this._renderWidth = new double?(num);
                    if ((this.Width.Type == DataGridUnitType.Star) || (this.Width.Type == DataGridUnitType.AutoStar))
                    {
                        this.View.OnColumnActualWidthChanged(this);
                    }
                }
            }
        }

        public DataGridView View { get; private set; }

        public DataGridLength Width
        {
            get
            {
                return this.Column.GetWidth();
            }
        }
    }
}
